package com.tuanzi.loan.business.service.family.impl;

import com.google.common.collect.Lists;
import com.starbaba.model.utils.JSONUtils;
import com.tuanzi.loan.business.entity.family.LoanAdvert;
import com.tuanzi.loan.business.entity.family.ProductInfo;
import com.tuanzi.loan.business.entity.family.ProductInfoTag;
import com.tuanzi.loan.business.entity.family.ProductInfoTagType;
import com.tuanzi.loan.business.entity.family.ProductManyHeadInfo;
import com.tuanzi.loan.business.entity.family.ProductTongdunManyHead;
import com.tuanzi.loan.business.repository.family.CommSysCodeRepository;
import com.tuanzi.loan.business.repository.family.LoanAdvertRepository;
import com.tuanzi.loan.business.repository.family.ProductInfoRepository;
import com.tuanzi.loan.business.service.common.CommRegionNewService;
import com.tuanzi.loan.business.service.family.ProductInfoService;
import com.tuanzi.loan.business.service.family.ProductInfoTagService;
import com.tuanzi.loan.business.service.family.ProductManyHeadInfoService;
import com.tuanzi.loan.business.service.family.ProductTongdunManyHeadInfoService;
import com.tuanzi.loan.core.aspect.Debug;
import com.tuanzi.loan.core.repository.JPAAuditRepository;
import com.tuanzi.loan.core.service.BaseAuditServiceImpl;
import com.tuanzi.loan.core.vo.PageSearcher;
import com.tuanzi.loan.vo.request.family.ProductInfoSearchRequest;
import com.tuanzi.loan.vo.response.family.ProductInfoSearchResponse;
import com.tuanzi.loan.vo.view.family.ProductInfoLongTag;
import com.tuanzi.loan.vo.view.family.product.ApplyCondition;
import com.tuanzi.loan.vo.view.family.product.ProductInfoView;
import com.tuanzi.server.loan_base.constant.LoanRedisKey;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.retry.RetryException;
import org.springframework.retry.annotation.Retryable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author Ray 2017/09/21
 */
@Slf4j
@Debug
@Service
@Transactional
@Retryable(value = { RetryException.class })
public class ProductInfoServiceImpl extends BaseAuditServiceImpl<ProductInfo, Long> implements ProductInfoService {

	@Autowired
	private StringRedisTemplate stringRedisTemplate;
	@Autowired
	private ProductInfoRepository productInfoRepository;
	@Autowired
	private ProductInfoTagService productInfoTagService;
	@Autowired
    private CommRegionNewService commRegionNewService;
	@Autowired
	private CommSysCodeRepository commSysCodeRepository;
	@Autowired
	private LoanAdvertRepository loanAdvertRepository;

	@Autowired
	private ProductManyHeadInfoService productManyHeadInfoService;

	@Autowired
	private ProductTongdunManyHeadInfoService productTongdunManyHeadInfoService;

	private final int ONLINE = 1;
	private final int OFFLINE = 0;

	@Override
	protected JPAAuditRepository<ProductInfo, Long> getRepository() {
		return productInfoRepository;
	}
	
	public Long copyProductInfo(Long productInfoId) {
		ProductInfo productInfo = productInfoRepository.findOne(productInfoId);
		ProductInfo newProductInfo = new ProductInfo();
		BeanUtils.copyProperties(productInfo, newProductInfo);
		newProductInfo.setId(null);
		newProductInfo.setCreateTime(new Date());
		newProductInfo.setUpdateTime(new Date());
		newProductInfo.setCreator(null);
		newProductInfo.setVersion(null);
		newProductInfo.setIsAddReplace(0);
		Long newProductInfoId = saveOrUpdate(newProductInfo).getId();

		List<ProductInfoTag> oldTabList = productInfoTagService.findAllByProductInfoId(productInfoId);
		List<ProductInfoTag> newTabList = new ArrayList<ProductInfoTag>();
		if(oldTabList != null && oldTabList.size() > 0) {
			for(ProductInfoTag oldTab : oldTabList) {
				ProductInfoTag newTab = new ProductInfoTag();
				BeanUtils.copyProperties(oldTab, newTab);
				
				newTab.setProductInfoId(newProductInfoId);
				newTab.setId(null);
				newTab.setCreateTime(new Date());
				newTab.setCreator(null);
				newTab.setUpdator(null);
				newTab.setUpdateTime(new Date());
				newTab.setVersion(null);
				newTabList.add(newTab);
			}
			productInfoTagService.saveOrUpdate(newTabList);
		}
		return newProductInfoId;
	}


	@Override
	public ProductInfoView loadProductInfoView(Long productInfoId) {
		ProductInfoView request = new ProductInfoView();

		ProductInfo productInfo = productInfoRepository.findOne(productInfoId);
		BeanUtils.copyProperties(productInfo, request);
		copyLongTag(productInfo, request);
		request.setProductInfoId(productInfo.getId());

		DateTime now = DateTime.now();
		if (productInfo.getEveryDayOnlineTime() != null) {
			request.setEveryDayOnlineTime(new DateTime(now.getYear(), now.getMonthOfYear(), now.getDayOfMonth(), 0, 0, 0).plusSeconds(productInfo.getEveryDayOnlineTime()).toDate());
		}
		if (productInfo.getEveryDayOfflineTime() != null) {
			request.setEveryDayOfflineTime(new DateTime(now.getYear(), now.getMonthOfYear(), now.getDayOfMonth(), 0, 0, 0).plusSeconds(productInfo.getEveryDayOfflineTime()).toDate());
		}
		if(request.getApplyCondition() == null){
			ApplyCondition applyCondition = new ApplyCondition();
			applyCondition.setAreaCondition(new ApplyCondition.AreaCondition());
			applyCondition.setBasicCondition(new ApplyCondition.BasicCondition());
			applyCondition.setBlackListCondition(new ApplyCondition.BlackListCondition());
			applyCondition.setLongLoanCondition(new ApplyCondition.LongLoanCondition());
			applyCondition.setProductId(productInfo.getId());
			request.setApplyCondition(applyCondition);
		}

		Map<ProductInfoTagType, List<ProductInfoTag>> productInfoTagMap = productInfoTagService.findAllByProductInfoId(productInfo.getId()).parallelStream()
				.collect(Collectors.groupingBy(ProductInfoTag::getTagType));

		request.setCredit(mapFromProductInfoTag(productInfoTagMap.get(ProductInfoTagType.CREDIT_CARD)));
		request.setIdentity(mapFromProductInfoTag(productInfoTagMap.get(ProductInfoTagType.IDENTITY)));
		request.setLoanNecessaryData(mapFromProductInfoTag(productInfoTagMap.get(ProductInfoTagType.LOAN_NECESSARY_DATA)));
		request.setLoanType(mapFromProductInfoTag(productInfoTagMap.get(ProductInfoTagType.LOAN_TYPE)));
		if (StringUtils.isNotBlank(productInfo.getAdvantage())) {
			request.setAdvantage(Arrays.asList(StringUtils.split(productInfo.getAdvantage(), ",")));
		}
		return request;
	}
	
	/**
	 * 展示长标签
	 */
	private void copyLongTag(ProductInfo productInfo, ProductInfoView request){
		String longTagJson = productInfo.getLongTagJson();
		if(StringUtils.isEmpty(longTagJson)) {
			return;
		}
		List<ProductInfoLongTag> tagList = JSONUtils.fromJsonArrayNew(longTagJson, ProductInfoLongTag.class);
		for(int i=0; i<tagList.size(); i++) {
			if(i == 0) {
				request.setLongTagImg1(tagList.get(0).getTag_img());
				request.setLongTagDesc1(tagList.get(0).getTag_desc());
			}
			if(i == 1) {
				request.setLongTagImg2(tagList.get(1).getTag_img());
				request.setLongTagDesc2(tagList.get(1).getTag_desc());
			}
		}
	}

	@Override
	public ProductInfo findProductInfoByName(String name) {
		return productInfoRepository.findProductInfoByName(name);
	}

	@Override
	public Page<ProductInfoSearchResponse> getApilist(PageSearcher<ProductInfoSearchRequest> pageSearcher) {
		return productInfoRepository.getApiList(pageSearcher.getSearchCondition(), pageSearcher.getPageable());
	}

	@Override
	public ProductInfoView saveOrUpdateProductInfoView(ProductInfoView view,ProductManyHeadInfo manyHeadInfo,List<ProductTongdunManyHead> tongdunManyHeads) {
		ProductInfo productInfo = null;
		Long productInfoId = view.getProductInfoId();
		if (view.getProductInfoId() != null) {
			productInfo = productInfoRepository.findOne(view.getProductInfoId());
		} else {
			productInfo = new ProductInfo();
		}
		
		BeanUtils.copyProperties(view, productInfo);
		if (view.getEveryDayOnlineTime() != null) {
			productInfo.setEveryDayOnlineTime(new DateTime(view.getEveryDayOnlineTime()).getSecondOfDay());
		}else{
			productInfo.setEveryDayOnlineTime(null);
		}
		if (view.getEveryDayOfflineTime() != null) {
			productInfo.setEveryDayOfflineTime(new DateTime(view.getEveryDayOfflineTime()).getSecondOfDay());
		}else{
			productInfo.setEveryDayOfflineTime(null);
		}
		handleLongTag(view ,productInfo);
		
		Map<String,String> regionMap = commRegionNewService.treeNodesToString(view.getSelectedRegionNodes());

		if(productInfo.getApiModelId() == null) {
			productInfo.setApiModelId("");
		}
		if(StringUtils.isEmpty(productInfo.getReceiptProductId())) {
			productInfo.setReceiptProductId("0");
		}
		if(StringUtils.isEmpty(productInfo.getReceiptModelId())) {
			productInfo.setReceiptModelId("0");
		}
		if (productInfo.getStatus() == null) {
			productInfo.setStatus(OFFLINE);
		}

		if (productInfo.getApi() == null) {
			productInfo.setApi(0);
		}

		if (productInfo.getUnionType() == null) {
			productInfo.setUnionType(0);
		}
		if (productInfo.getAllId() == null){
			productInfo.setAllId(0);
		}

		if (CollectionUtils.isNotEmpty(view.getAdvantage())) {
			productInfo.setAdvantage(view.getAdvantage().stream().collect(Collectors.joining(",")));
		}

		if (productInfo.getId() != null) {
			productInfoTagService.delete(productInfoTagService.findAllByProductInfoId(productInfo.getId()));
		}

		productInfo = saveOrUpdate(productInfo);
		view.setProductInfoId(productInfo.getId());
		List<ProductInfoTag> loanTypeTag = structureProductInfoTag(productInfo.getId(), ProductInfoTagType.LOAN_TYPE, view.getLoanType());
		List<ProductInfoTag> identityTag = structureProductInfoTag(productInfo.getId(), ProductInfoTagType.IDENTITY, view.getIdentity());
		List<ProductInfoTag> creditTag = structureProductInfoTag(productInfo.getId(), ProductInfoTagType.CREDIT_CARD, view.getCredit());
		List<ProductInfoTag> loanNecessaryData = structureProductInfoTag(productInfo.getId(), ProductInfoTagType.LOAN_NECESSARY_DATA, view.getLoanNecessaryData());

		productInfoTagService.saveOrUpdate(identityTag);
		productInfoTagService.saveOrUpdate(loanTypeTag);
		productInfoTagService.saveOrUpdate(creditTag);
		productInfoTagService.saveOrUpdate(loanNecessaryData);

		//保存风控信息
		if (manyHeadInfo.getActivityId() == null) manyHeadInfo.setActivityId(productInfo.getId());
		productManyHeadInfoService.saveOrUpdate(manyHeadInfo);

		//保存同盾多头信息
		for (ProductTongdunManyHead e : tongdunManyHeads){
			if (e.getActivityId() == null){
				e.setActivityId(productInfo.getId());
			}
		}
		for (int i=0;i<tongdunManyHeads.size();i++){
			ProductTongdunManyHead productTongdunManyHead = productTongdunManyHeadInfoService.saveOrUpdate(tongdunManyHeads.get(i));
			tongdunManyHeads.set(i,productTongdunManyHead);
		}

		cleanRedis(productInfo.getId());
		cleanSpaceRedis();
		return view;
	}
	
	/**
	 * 长标签数据转换成json
	 * @param view
	 * @param productInfo
	 */
	private void handleLongTag(ProductInfoView view ,ProductInfo productInfo){
		List<ProductInfoLongTag> tagList = new ArrayList<ProductInfoLongTag>();
		tagList.add(new ProductInfoLongTag(view.getLongTagImg1() ,view.getLongTagDesc1()));
		tagList.add(new ProductInfoLongTag(view.getLongTagImg2() ,view.getLongTagDesc2()));
		String tagJson = JSONUtils.toJsonString(tagList);
		productInfo.setLongTagJson(tagJson);
	}
	
	private void cleanRedis(Long productId) {
		stringRedisTemplate.delete(LoanRedisKey.LOAN_ACTIVITY_INFO + productId);
		stringRedisTemplate.delete(LoanRedisKey.LOAN_ONLINE_ACTIVITY_INFO + productId);
		stringRedisTemplate.delete(LoanRedisKey.LOAN_DETAIL_ACTIVITY_ID + productId);
		stringRedisTemplate.delete(LoanRedisKey.LOAN_PRODUCT_TAGS + productId);
	}

	private void cleanSpaceRedis() {
		List<Integer> adList = commSysCodeRepository.findAdvertiseIdList();
		stringRedisTemplate.delete(adList.stream().map(x -> LoanRedisKey.LOAN_SPACE_LIST + x).collect(Collectors.toList()));
	}

	private List<ProductInfoTag> structureProductInfoTag(Long productInfoId, ProductInfoTagType tagType, List<String> tagValues) {
		return tagValues.parallelStream().map(x -> {
			ProductInfoTag productInfoTag = new ProductInfoTag();
			productInfoTag.setProductInfoId(productInfoId);
			productInfoTag.setTagType(tagType);
			productInfoTag.setTagValue(x);
			return productInfoTag;
		}).collect(Collectors.toList());
	}

	private List<String> mapFromProductInfoTag(List<ProductInfoTag> productInfoTags) {
		if (CollectionUtils.isEmpty(productInfoTags)) {
			return Lists.newArrayList();
		}
		return productInfoTags.parallelStream().map(ProductInfoTag::getTagValue).map(x -> x.toString()).collect(Collectors.toList());
	}

	@Override
	public Page<ProductInfoSearchResponse> list(PageSearcher<ProductInfoSearchRequest> pageSearcher) {
		return productInfoRepository.list(pageSearcher.getSearchCondition(), pageSearcher.getPageable());
	}

	@Override
	public void online(ProductInfo productInfo) {
		online(Lists.newArrayList(productInfo));
	}

	@Override
	public void online(List<ProductInfo> productInfos) {
		productInfos.parallelStream().peek(x -> {
			x.setStatus(ONLINE);
			x.setOnlineTime(new Date());
		}).forEach(x -> {
			this.saveOrUpdate(x);
			cleanRedis(x.getId());
		});
		cleanSpaceRedis();
	}

	@Override
	public void offline(List<ProductInfo> productInfos) {
		productInfos.parallelStream().peek(x -> {
			x.setStatus(OFFLINE);
			x.setOnlineTime(new Date());
		}).forEach(x -> {
			this.saveOrUpdate(x);
			cleanRedis(x.getId());
		});
		cleanSpaceRedis();
	}

	@Override
	public void offline(ProductInfo productInfo) {
		offline(Lists.newArrayList(productInfo));
	}

	@Override
	public List<ProductInfoSearchResponse> listAllUnionProductInfos() {
		return productInfoRepository.listAllUnionProductInfo();
	}

	/**
	 * 查询产品列表作为下拉框
	 * @return
	 */
	@Override
	public List<ProductInfo> listAllProductInfo() {
		return productInfoRepository.listAllProductInfo();
	}

	@Override
	public List<ProductInfo> listAllProductInfoByStatus(Integer status) {
		return productInfoRepository.listAllProductInfoByStatus(status);
	}

	/**
	 * 查询公司所有的产品
	 * @param companyId
	 * @return
	 */
	@Override
	public List<ProductInfo> listAllProductInfoByCompanyId(Long companyId) {
		return productInfoRepository.listAllProductInfoByCompanyId(companyId);
	}


}
